﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using IPC.Communication.Core;
using IPC.Communication.Core.Address;
using IPC.Communication.Core.IMessage;
using IPC.Communication.Core.Net;
using IPC.Communication.Reflection;

namespace IPC.Communication.Profinet.Fuji
{
    public class FujiCommandSettingType : NetworkDeviceBase
    {
        private bool dataSwap = false;

        public bool DataSwap
        {
            get
            {
                return dataSwap;
            }
            set
            {
                dataSwap = value;
                if (value)
                {
                    base.ByteTransform = new RegularByteTransform();
                }
                else
                {
                    base.ByteTransform = new ReverseBytesTransform();
                }
            }
        }

        public FujiCommandSettingType()
        {
            base.ByteTransform = new ReverseBytesTransform();
            base.WordLength = 2;
        }

        public FujiCommandSettingType(string ipAddress, int port)
            : this()
        {
            IpAddress = ipAddress;
            Port = port;
        }

        protected override INetMessage GetNewNetMessage()
        {
            return new FujiCommandSettingTypeMessage();
        }

        protected override OperateResult<byte[]> UnpackResponseContent(byte[] send, byte[] response)
        {
            return UnpackResponseContentHelper(send, response);
        }

        [HslMqttApi("ReadByteArray", "")]
        public override OperateResult<byte[]> Read(string address, ushort length)
        {
            OperateResult<byte[]> operateResult = BuildReadCommand(address, length);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            return ReadFromCoreServer(operateResult.Content);
        }

        [HslMqttApi("WriteByteArray", "")]
        public override OperateResult Write(string address, byte[] value)
        {
            OperateResult<byte[]> operateResult = BuildWriteCommand(address, value);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            return ReadFromCoreServer(operateResult.Content);
        }

        //[AsyncStateMachine(typeof(<ReadAsync>d__6))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<byte[]>> ReadAsync(string address, ushort length)
        //{
        //    <ReadAsync>d__6 stateMachine = new <ReadAsync>d__6();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__7))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, byte[] value)
        //{
        //    <WriteAsync>d__7 stateMachine = new <WriteAsync>d__7();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        [HslMqttApi("ReadByte", "")]
        public OperateResult<byte> ReadByte(string address)
        {
            return ByteTransformHelper.GetResultFromArray(Read(address, 1));
        }

        [HslMqttApi("WriteByte", "")]
        public OperateResult Write(string address, byte value)
        {
            return Write(address, new byte[1]
		{
			value
		});
        }

        //[AsyncStateMachine(typeof(<ReadByteAsync>d__10))]
        //[DebuggerStepThrough]
        //public Task<OperateResult<byte>> ReadByteAsync(string address)
        //{
        //    <ReadByteAsync>d__10 stateMachine = new <ReadByteAsync>d__10();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__11))]
        //[DebuggerStepThrough]
        //public Task<OperateResult> WriteAsync(string address, byte value)
        //{
        //    <WriteAsync>d__11 stateMachine = new <WriteAsync>d__11();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public override string ToString()
        {
            return String.Format("FujiCommandSettingType[{0}:{1}]", IpAddress, Port);
        }

        public static OperateResult<byte[]> BuildReadCommand(string address, ushort length)
        {
            OperateResult<FujiCommandSettingTypeAddress> operateResult = FujiCommandSettingTypeAddress.ParseFrom(address, length);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            return OperateResult.CreateSuccessResult(new byte[9]
		{
			0,
			0,
			0,
			operateResult.Content.DataCode,
			4,
			BitConverter.GetBytes(operateResult.Content.AddressStart)[0],
			BitConverter.GetBytes(operateResult.Content.AddressStart)[1],
			BitConverter.GetBytes(operateResult.Content.Length)[0],
			BitConverter.GetBytes(operateResult.Content.Length)[1]
		});
        }

        public static OperateResult<byte[]> BuildWriteCommand(string address, byte[] value)
        {
            OperateResult<FujiCommandSettingTypeAddress> operateResult = FujiCommandSettingTypeAddress.ParseFrom(address, 0);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            byte[] array = new byte[9 + value.Length];
            array[0] = 1;
            array[1] = 0;
            array[2] = 0;
            array[3] = operateResult.Content.DataCode;
            array[4] = (byte)(4 + value.Length);
            array[5] = BitConverter.GetBytes(operateResult.Content.AddressStart)[0];
            array[6] = BitConverter.GetBytes(operateResult.Content.AddressStart)[1];
            array[7] = BitConverter.GetBytes(operateResult.Content.Length)[0];
            array[8] = BitConverter.GetBytes(operateResult.Content.Length)[0];
            value.CopyTo(array, 9);
            return OperateResult.CreateSuccessResult(array);
        }

        public static string GetErrorText(int error)
        {
            switch (error)
            {
                case 18:
                    return "Write of data to the program area";
                case 32:
                    return "Non-existing CMND code";
                case 33:
                    return "Input data is not in the order of data corresponding to CMND";
                case 34:
                    return "Operation only from the loader is effective. Operation from any other node is disabled";
                case 36:
                    return "A non-existing module has been specified";
                case 50:
                    return "An address out of the memory size has been specified";
                default:
                    return StringResources.Language.UnknownError;
            }
        }

        public static OperateResult<byte[]> UnpackResponseContentHelper(byte[] send, byte[] response)
        {
            if (response[1] != 0)
            {
                return new OperateResult<byte[]>(GetErrorText(response[1]));
            }
            return OperateResult.CreateSuccessResult(response.RemoveBegin(10));
        }
    }
}